package com.rybbaby.tss.core.utils;

import org.apache.commons.lang.ArrayUtils;

import java.io.*;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @description java Bean 操作工具类
 * @outhor xiejinwei
 * @create 2017-11-22 0:58
 */
public class BeanUtils extends org.apache.commons.beanutils.BeanUtils {

    /**
     * 将一个集合中的Map中的数据封装到一个集合实体中
     * 必要条件：
     * 1、list泛型map中的key与实体类中的字段名一致
     * 2、list泛型map中key对应值的类型和实体类中字段与key相同的数据类型一致
     *
     * @param cls        封装之后实体类的Class类型
     * @param list       需要封装的list集合
     * @param ignoreKeys map中不需要进行封装的key
     * @param <T>        封装的class类型
     * @return
     * @throws IllegalAccessException
     * @throws InstantiationException
     */
    public static <T> List<T> populate(Class<T> cls, List<Map<String, Object>> list, String... ignoreKeys) throws IllegalAccessException, InstantiationException {
        if (cls == null) {
            throw new IllegalAccessException("param 'cls' is required and this is not null!");
        }
        List<T> result = new ArrayList<>();
        if (list != null && !list.isEmpty()) {
            for (Map<String, Object> map : list) {
                T populate = populate(cls, map, ignoreKeys);
                if (populate != null) {
                    result.add(populate);
                }
            }
        }
        return result;
    }

    /**
     * 将一个Map中的数据封装到一个实体中
     * 必要条件：
     * 1、map中的key与实体类中的字段名一致
     * 2、map中key对应值的类型和实体类中字段与key相同的数据类型一致
     *
     * @param cls        封装之后实体类的Class类型
     * @param map        需要封装的map集合
     * @param ignoreKeys map中不需要进行封装的key
     * @param <T>        封装的class类型
     * @return
     * @throws IllegalAccessException
     * @throws InstantiationException
     */
    public static <T> T populate(Class<T> cls, Map<String, Object> map, String... ignoreKeys) throws IllegalAccessException, InstantiationException {
        if (cls == null) {
            throw new IllegalAccessException("param 'cls' is required and this is not null!");
        }
        T t = cls.newInstance();
        if (map != null && !map.isEmpty()) {
            Field[] fields = cls.getDeclaredFields();
            for (Field field : fields) {
                String name = field.getName();
                if (ArrayUtils.indexOf(ignoreKeys, name) != -1) {
                    continue;
                }
                field.setAccessible(true);
                Class<?> type = field.getType();
                String typeName = type.getTypeName();
                if (map.containsKey(name)) {
                    Object objVal = map.get(name);
                    if (objVal != null) {
                        Class<?> objValType = objVal.getClass();
                        List<String> objValTypes = new ArrayList<>();
                        getSuperClassTypeNames(objValType, objValTypes);
                        objValTypes.add(objValType.getTypeName());
                        if (objValTypes.contains(typeName)) {
                            field.set(t, objVal);
                        }
                    }
                }
            }
        }
        return t;
    }

    /**
     * 获取指定类的所有父类类型名称
     *
     * @param cls   需要查找父类的class
     * @param types 存放所有父类类型名称的容器
     */
    public static void getSuperClassTypeNames(Class<?> cls, List<String> types) {
        if (cls != null) {
            Class<?> superclass = cls.getSuperclass();
            if (superclass != null) {
                getSuperClassTypeNames(superclass, types);
                types.add(superclass.getTypeName());
            }
        }
    }

    /**
     * 对象属性浅复制
     *
     * @param source                 源对象
     * @param target                 接收的对象
     * @param coverNullToTargetField 是否将source对象中值为null的属性覆盖target相应的属性
     * @param ignoreFields           不需要从source中复制的属性
     * @param <T>                    源对象和目标对象的类泛型
     * @return
     */
    public static <T> void copyProperties(T source, T target, boolean coverNullToTargetField, String... ignoreFields) throws IllegalAccessException {
        if (source == null) {
            throw new IllegalAccessException("param 'source' is required and this is not null");
        }
        if (target == null) {
            throw new IllegalAccessException("param 'target' is required and this is not null");
        }
        boolean isExistsIngoreField = ignoreFields != null && ignoreFields.length > 0;
        Class<?> aClass = target.getClass();
        Field[] fields = aClass.getDeclaredFields();
        for (Field field : fields) {
            if (isExistsIngoreField) {
                if (ArrayUtils.contains(ignoreFields, field.getName())) {
                    continue;
                }
            }
            field.setAccessible(true);
            Object sourceFieldVal = field.get(source);
            if (sourceFieldVal != null || (sourceFieldVal == null && coverNullToTargetField)) {
                field.set(target, sourceFieldVal);
            }
        }
    }

    /**
     * 对象深度复制
     *
     * @param t   需要复制的对象
     * @param <T> 需要复制的对象类泛型，该类和该类中的所有属性都必须要实现 java.io.Serializable
     * @return
     * @throws IOException
     * @throws ClassNotFoundException
     */
    public static <T> T deepClone(T t) throws IOException, ClassNotFoundException {
        //将对象写到流里(串行化)
        ByteArrayOutputStream bo = new ByteArrayOutputStream();
        ObjectOutputStream oo = new ObjectOutputStream(bo);
        oo.writeObject(t);
        //从流里读出来(并行化)
        ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray());
        ObjectInputStream oi = new ObjectInputStream(bi);
        return (T) oi.readObject();
    }
}
